package net.stogi.dsper.ui.client;

import java.util.HashMap;
import java.util.Map;

import net.stogi.common.gwt.dispatch.client.core.ActionManager;
import net.stogi.common.gwt.frame.client.core.AbstractApplicationManager;
import net.stogi.common.gwt.frame.client.core.CacheManager;
import net.stogi.common.gwt.frame.client.core.EventBus;
import net.stogi.common.gwt.frame.client.core.LayoutManager;
import net.stogi.common.gwt.frame.client.module.Module;
import net.stogi.common.gwt.frame.client.module.ModuleFactoryRegistry;
import net.stogi.common.gwt.frame.client.module.ModuleFactory.ModuleInstanceCallback;
import net.stogi.dsper.ui.client.module.dataobject.DataObjectModule;
import net.stogi.dsper.ui.client.module.dataobject.DataObjectModuleFactory;
import net.stogi.dsper.ui.client.module.dataobject.OpenDataObjectListEvent;
import net.stogi.dsper.ui.client.module.datasource.DataSourceModule;
import net.stogi.dsper.ui.client.module.datasource.DataSourceModuleFactory;
import net.stogi.dsper.ui.client.module.login.LoginInfoModule;
import net.stogi.dsper.ui.client.module.login.LoginInfoModuleFactory;
import net.stogi.dsper.ui.client.module.login.UserLoggedInEvent;
import net.stogi.dsper.ui.client.module.menu.MenuModule;
import net.stogi.dsper.ui.client.module.menu.MenuModuleFactory;
import net.stogi.dsper.ui.client.module.tag.TagEditorModule;
import net.stogi.dsper.ui.client.module.tag.TagEditorModuleFactory;
import net.stogi.dsper.ui.client.module.user.UserModule;
import net.stogi.dsper.ui.client.module.user.UserModuleFactory;
import net.stogi.dsper.ui.shared.GetPrincipalDataAction;
import net.stogi.dsper.ui.shared.GetPrincipalDataResult;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class DsperUiApplicationManagerImpl extends AbstractApplicationManager {

	private final Map<Class<? extends Module>, Module> moduleMap = new HashMap<Class<? extends Module>, Module>();

	public DsperUiApplicationManagerImpl(ActionManager actionManager, CacheManager cacheManager, EventBus eventBus,
			LayoutManager layoutManager, ModuleFactoryRegistry moduleFactoryRegistry) {
		super(actionManager, cacheManager, eventBus, layoutManager, moduleFactoryRegistry);
		initFactories();
		initHandlers();
		initModules();
	}

	@Override
	public void run() {
		actionManager.execute(new GetPrincipalDataAction(), new AsyncCallback<GetPrincipalDataResult>() {

			@Override
			public void onFailure(Throwable caught) {
				GWT.log("GetPrincipalDataAction: failed", caught);
			}

			@Override
			public void onSuccess(GetPrincipalDataResult result) {
				GWT.log("GetPrincipalDataAction: success: [result.principalData.username = '" + result.getPrincipalData().getUsername()
						+ "']", null);
				cacheManager.put("principalData", result.getPrincipalData());
				eventBus.fireEvent(new UserLoggedInEvent(result.getPrincipalData()));
				eventBus.fireEvent(new OpenDataObjectListEvent());
				layoutManager.layout();
			}
		});
	}

	@Override
	protected void initFactories() {
		moduleFactoryRegistry.registerFactory(DataObjectModule.class, new DataObjectModuleFactory(actionManager, eventBus));
		moduleFactoryRegistry.registerFactory(DataSourceModule.class, new DataSourceModuleFactory(actionManager, eventBus));
		moduleFactoryRegistry.registerFactory(LoginInfoModule.class, new LoginInfoModuleFactory(actionManager, eventBus));
		moduleFactoryRegistry.registerFactory(MenuModule.class, new MenuModuleFactory(actionManager, eventBus));
		moduleFactoryRegistry.registerFactory(TagEditorModule.class, new TagEditorModuleFactory(actionManager, eventBus));
		moduleFactoryRegistry.registerFactory(UserModule.class, new UserModuleFactory(actionManager, eventBus));
	}

	@Override
	protected void initHandlers() {}

	@Override
	protected void initModules() {
		moduleFactoryRegistry.findFactory(MenuModule.class).getInstance(new ModuleInstanceCallback<MenuModule>() {

			@Override
			public void onBeforeModuleInstanceCreated() {}

			@Override
			public void onModuleInstanceCreated(MenuModule module) {
				moduleMap.put(MenuModule.class, module);
				layoutManager.addWidget("west", module.getWidget(MenuModule.MENU_WIDGET));
			}
		});
		moduleFactoryRegistry.findFactory(DataObjectModule.class).getInstance(new ModuleInstanceCallback<DataObjectModule>() {

			@Override
			public void onBeforeModuleInstanceCreated() {}

			@Override
			public void onModuleInstanceCreated(DataObjectModule module) {
				moduleMap.put(DataObjectModule.class, module);
				layoutManager.addWidget("center", module.getWidget(DataObjectModule.DATA_OBJECT_LIST_WIDGET));
				layoutManager.addWidget("east", module.getWidget(DataObjectModule.DATA_OBJECT_PREVIEW_WIDGET));
			}
		});
		moduleFactoryRegistry.findFactory(DataSourceModule.class).getInstance(new ModuleInstanceCallback<DataSourceModule>() {

			@Override
			public void onBeforeModuleInstanceCreated() {}

			@Override
			public void onModuleInstanceCreated(DataSourceModule module) {
				moduleMap.put(DataSourceModule.class, module);
				layoutManager.addWidget("east", module.getWidget(DataSourceModule.DATA_SOURCE_EDITOR_WIDGET));
				layoutManager.addWidget("center", module.getWidget(DataSourceModule.DATA_SOURCE_LIST_WIDGET));
			}
		});
		moduleFactoryRegistry.findFactory(LoginInfoModule.class).getInstance(new ModuleInstanceCallback<LoginInfoModule>() {

			@Override
			public void onBeforeModuleInstanceCreated() {}

			@Override
			public void onModuleInstanceCreated(LoginInfoModule module) {
				moduleMap.put(LoginInfoModule.class, module);
				layoutManager.addWidget("north", module.getWidget(LoginInfoModule.LOGIN_INFO_WIDGET));
			}
		});
		moduleFactoryRegistry.findFactory(TagEditorModule.class).getInstance(new ModuleInstanceCallback<TagEditorModule>() {

			@Override
			public void onBeforeModuleInstanceCreated() {}

			@Override
			public void onModuleInstanceCreated(TagEditorModule module) {
				moduleMap.put(TagEditorModule.class, module);
				layoutManager.addWidget("center", module.getWidget(TagEditorModule.TAG_EDITOR_WIDGET));
			}
		});
		moduleFactoryRegistry.findFactory(UserModule.class).getInstance(new ModuleInstanceCallback<UserModule>() {

			@Override
			public void onBeforeModuleInstanceCreated() {}

			@Override
			public void onModuleInstanceCreated(UserModule module) {
				moduleMap.put(UserModule.class, module);
				layoutManager.addWidget("center", module.getWidget(UserModule.USER_PROFILE_LIST_WIDGET));
				layoutManager.addWidget("east", module.getWidget(UserModule.USER_PROFILE_EDITOR_WIDGET));
			}
		});
	}
}
